// =====================================================

#ifndef LONGKEY_BASE_UTILS_H_
#define LONGKEY_BASE_UTILS_H_

#include <windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <map>
#include <vector>
#include <atlsecurity.h>
#include "constants.h"
#include "static_assert.h"
#include "debug.h"
#include "logging.h"
#include "time.h"

// These definitions are not in any current Microsoft SDK header file. Taken
// from platformsdk/v6_1/files/Include/ObjIdl.h.
MIDL_INTERFACE("0000015B-0000-0000-C000-000000000046")
IGlobalOptions : public IUnknown {
public:
	virtual HRESULT STDMETHODCALLTYPE Set(
		/* [in] */ DWORD dwProperty,
		/* [in] */ ULONG_PTR dwValue) = 0;

	virtual HRESULT STDMETHODCALLTYPE Query(
		/* [in] */ DWORD dwProperty,
		/* [out] */ ULONG_PTR *pdwValue) = 0;
};

enum __MIDL___MIDL_itf_objidl_0000_0047_0001 {
	COMGLB_EXCEPTION_HANDLING  = 1,
	COMGLB_APPID  = 2
};

enum __MIDL___MIDL_itf_objidl_0000_0047_0002 {
	COMGLB_EXCEPTION_HANDLE  = 0,
	COMGLB_EXCEPTION_DONOT_HANDLE  = 1
};

// Determines whether to run ClickOnce components. This constant is not defined
// in the SDK headers.
#ifndef URLACTION_MANAGED_UNSIGNED
#define URLACTION_MANAGED_UNSIGNED (0x00002004)
#endif

ULONGLONG VersionFromString(const CString& s);

CString StringFromVersion(ULONGLONG version);

// Gets current directory
CString GetCurrentDir();

// Creates a unique file name using a new guid. Does not check for
// presence of this file in the directory.
HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name);

// Gets security descriptor with a DACL that grants the admin_access_mask to
// Admins and System, and the non_admin_access_mask to Interactive.
void GetEveryoneDaclSecurityDescriptor(CSecurityDesc* sd,
									   ACCESS_MASK admin_access_mask,
									   ACCESS_MASK non_admin_access_mask);

// Get security descriptor containing a DACL that grants the ACCESS_MASK access
// to admins and system.
void GetAdminDaclSecurityDescriptor(CSecurityDesc* sd, ACCESS_MASK accessmask);

// Get security attributes containing a DACL that grant the ACCESS_MASK access
// to admins and system.
void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,
									ACCESS_MASK accessmask);

// This method is intended to be called by same or lower integrity COM clients.
// Calls ::CoInitializeSecurity with the default DACL. Servers are allowed to
// impersonate the client.
HRESULT InitializeClientSecurity();

// This method calls ::CoInitializeSecurity with security settings and ACLs of
// callers that are allowed access to the COM server. Clients can only identify
// the server, and custom marshaling as well as activate-as-activator are
// disallowed.
// * If the bool is set, a DACL that provides COM_RIGHTS_EXECUTE access
// for medium-integrity callers is set.
// * If the bool is not set, but the caller is Local System, the function will
// set a security descriptor that also allows the Administrators group access to
// the COM server.
HRESULT InitializeServerSecurity(bool allow_calls_from_medium);

// Ensures that the COM marshaling machinery does not eat crashes.
HRESULT DisableCOMExceptionHandling();

// Merges an Allowed ACE into a named object. If the ACE already exists in the
// DACL with the same permissions (or a superset) and the same ACE flags, the
// merge is skipped.
HRESULT AddAllowedAce(const TCHAR* object_name,
					  SE_OBJECT_TYPE object_type,
					  const CSid& sid,
					  ACCESS_MASK required_permissions,
					  uint8 required_ace_flags);

struct NamedObjectAttributes {
	CString name;
	CSecurityAttributes sa;
};

// For machine and local system, the prefix would be "Global\G{obj_name}".
// For user, the prefix would be "Global\G{user_sid}{obj_name}".
// For machine objects, returns a security attributes that gives permissions to
// both Admins and SYSTEM. This allows for cases where SYSTEM creates the named
// object first. The default DACL for SYSTEM will not allow Admins access.
void GetNamedObjectAttributes(const TCHAR* base_name,
							  bool is_machine,
							  NamedObjectAttributes* attr);

// Returns true if the current process is running as SYSTEM.
HRESULT IsSystemProcess(bool* is_system_process);


// Returns true if the user of the current process is Local System or it has an
// interactive session: console, terminal services, or fast user switching.
HRESULT IsUserLoggedOn(bool* is_logged_on);

// Returns true if URLACTION_MANAGED_UNSIGNED is disabled for the Internet zone
// for the current user.
bool IsClickOnceDisabled();

// Wrapper around ::GetProcAddress().
template <typename T>
bool GPA(HMODULE module, const char* function_name, T* function_pointer) {
	ASSERT1(module);
	ASSERT1(function_name);
	ASSERT1(function_pointer);

	*function_pointer = reinterpret_cast<T>(::GetProcAddress(module,
		function_name));
	if (NULL == *function_pointer) {
		UTIL_LOG(LW, (_T("GetProcAddress failed [%s]"), CA2T(function_name)));
	}
	return NULL != *function_pointer;
}

#define GPA_WRAP(module,                                                    \
	function,                                                  \
	proto,                                                     \
	call,                                                      \
	calling_convention,                                        \
	result_type,                                               \
	result_error)                                              \
	typedef result_type (calling_convention *function##_pointer) proto;         \
	inline result_type function##Wrap proto {                                   \
	HINSTANCE module_instance = ::GetModuleHandle(_T(#module));               \
	ASSERT1(module_instance);                                                 \
	if (!module_instance) {                                                   \
	return result_error;                                                    \
	}                                                                         \
	function##_pointer fn = NULL;                                             \
	return GPA(module_instance, #function, &fn) ? (*fn) call : result_error;  \
}

GPA_WRAP(kernel32.dll,
		 AttachConsole,
		 (DWORD process_id),
		 (process_id),
		 WINAPI,
		 BOOL,
		 0);

// Private Object Namespaces for Vista and above. More information here:
// http://msdn2.microsoft.com/en-us/library/ms684295(VS.85).aspx
GPA_WRAP(kernel32.dll,
		 CreateBoundaryDescriptorW,
		 (LPCWSTR boundary_name, ULONG flags),
		 (boundary_name, flags),
		 WINAPI,
		 HANDLE,
		 NULL);
GPA_WRAP(kernel32.dll,
		 AddSIDToBoundaryDescriptor,
		 (HANDLE* boundary_descriptor, PSID required_sid),
		 (boundary_descriptor, required_sid),
		 WINAPI,
		 BOOL,
		 FALSE);
GPA_WRAP(kernel32.dll,
		 CreatePrivateNamespaceW,
		 (LPSECURITY_ATTRIBUTES private_namespace_attributes, LPVOID boundary_descriptor, LPCWSTR alias_prefix),  // NOLINT
		 (private_namespace_attributes, boundary_descriptor, alias_prefix),
		 WINAPI,
		 HANDLE,
		 NULL);
GPA_WRAP(kernel32.dll,
		 OpenPrivateNamespaceW,
		 (LPVOID boundary_descriptor, LPCWSTR alias_prefix),
		 (boundary_descriptor, alias_prefix),
		 WINAPI,
		 HANDLE,
		 NULL);

bool IsPrivateNamespaceAvailable();


HRESULT PinModuleIntoProcess(const CString& module_name);

// Creates a directory with default security.
//   S_OK:    Created directory
//   S_FALSE: Directory already existed
//   E_FAIL:  Couldn't create
HRESULT CreateDir(const TCHAR* dirname, LPSECURITY_ATTRIBUTES security_attr);

// Gets the path for the specified special folder.
HRESULT GetFolderPath(int csidl, CString* path);

// Returns true if this directory name is 'safe' for deletion:
//  - it doesn't contain ".."
//  - it doesn't specify a drive root
bool SafeDirectoryNameForDeletion(const TCHAR* dir_name);

// Deletes a directory and its files.
HRESULT DeleteDirectory(const TCHAR* ir_name);

// Deletes all files in a directory.
HRESULT DeleteDirectoryFiles(const TCHAR* dir_name);

// Deletes all files in a directory matching a wildcard.
HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name);

// Deletes either a file or directory before or after reboot.
HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname);

// Gets the size of all files in a directory.
// Aborts counting if one of the maximum criteria is reached.
HRESULT SafeGetDirectorySize(const TCHAR* dir_name,
							 uint64* size,
							 HANDLE shutdown_event,
							 uint64 max_size,
							 int max_depth,
							 int max_file_count,
							 int max_running_time_ms);

// Gets size of all files in a directory.
HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size);

enum TimeCategory {
	PAST = 0,  // older than 40 years from now
	FUTURE,    // in the future by > 1 day
	PRESENT,   // neither ANCIENT nor FUTURE
};

TimeCategory GetTimeCategory(time64 t);

// Returns true if a given time is likely to be valid.
bool IsValidTime(time64 t);

// Gets a time64 value.
// If the value is greater than the
// max value, then SetValue will be called using the max_value.
//
//  Args:
//   full_key_name:   the reg keyto read to get the time value.
//   value_name:      the name for the reg key value to be read.
//                    (may be NULL to get the default value)
//   max_time:        the maximum value for the reg key.
//   value:           the time value read.  May not be set on failure.
//   limited_value:   true iff will be set if the value was
//                    changed (and resaved). (NULL is allowable.)
HRESULT GetLimitedTimeValue(const TCHAR* full_key_name,
							const TCHAR* value_name,
							time64 max_time,
							time64* value,
							bool* limited_value);

// Gets a time64 value trying reg keys successively if there is a
// failure in getting a value.
//
// Typically used when there is a user value and a default value if the
// user has none.
//
//  Args:
//   full_key_names:  a list of reg keys to try successively (starting
//                    with index 0) to read to get the time value.  The
//                    attempts stops as soon as there is a successful read or
//                    when all keys have been tried.
//   key_names_length: number of keys in full_key_names.
//   value_name:      the name for the reg key value to be read.
//                    (may be NULL to get the default value)
//   max_time:        the maximum value for the reg key.
//   value:           the time value read.  May not be set on failure.
//   limited_value:   true iff will be set if the value was
//                    changed (and resaved). (NULL is allowable.)
HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],
							 int key_names_length,
							 const TCHAR* value_name,
							 time64 max_time,
							 time64* value,
							 bool* limited_value);

// Convert milliseconds to a relative time in units of 100ns, suitable for use
// with waitable timers
LARGE_INTEGER MSto100NSRelative(DWORD ms);

// TODO: remove from public interface.
inline void WINAPI NullAPCFunc(ULONG_PTR) {}

// Forces rasman.dll load to avoid a crash in wininet.
void EnsureRasmanLoaded();

// Returns if the HRESULT argument is a COM error
// TODO: use an ANONYMOUS_VARIABLE to avoid the situation in which the
// macro gets called like RET_IF_FAILED(hr);
// For now, use a quick fix hr -> __hr. Leading underscore names are not to be
// used in application code.
#define RET_IF_FAILED(x)    \
	do {                    \
	HRESULT __hr(x);      \
	if (FAILED(__hr)) {   \
	return __hr;        \
	}                     \
	} while (false)

// return error if the first argument evaluates to false
#define RET_IF_FALSE(x, err)  \
	do {                        \
	if (!(x)) {               \
	return err;             \
	}                         \
	} while (false)

// return false if the HRESULT argument is a COM error
#define RET_FALSE_IF_FAILED(x)  \
	do {                          \
	if (FAILED(x)) {            \
	return false;             \
	}                           \
	} while (false)

// return true if the HRESULT argument is a COM error
#define RET_TRUE_IF_FAILED(x)   \
	do {                          \
	if (FAILED(x)) {            \
	return true;              \
	}                           \
	} while (false)

// return if the HRESULT argument evaluates to FAILED - but also assert
// if failed
#define RET_IF_FAILED_ASSERT(x, msg) \
	do {                             \
	HRESULT hr(x);                 \
	if (FAILED(hr)) {              \
	ASSERT(false, msg);          \
	return hr;                   \
	}                              \
	} while (false)


// return if the HRESULT argument evaluates to FAILED - but also log an error
// message if failed
#define RET_IF_FAILED_LOG(x, cat, msg) \
	do {                               \
	HRESULT hr(x);                   \
	if (FAILED(hr)) {                \
	LC_LOG(cat, LEVEL_ERROR, msg); \
	return hr;                     \
	}                                \
	} while (false)

// return if the HRESULT argument evaluates to FAILED - but also REPORT an error
// message if failed
#define RET_IF_FAILED_REPORT(x, msg, n) \
	do {                                \
	HRESULT hr(x);                    \
	if (FAILED(hr)) {                 \
	REPORT(false, R_ERROR, msg, n); \
	return hr;                      \
	}                                 \
	} while (false)

// Initializes a POD to zero.
// Using this function requires discipline. Don't use for types that have a
// v-table or virtual bases.
template <typename T>
inline void SetZero(T& p) {   // NOLINT
	// Guard against the easy mistake of
	//    foo(int *p) { SetZero(p); } instead of
	//                  SetZero(*p);
	// which it should be.
	STATIC_ASSERT(sizeof(p) != sizeof(void*));    // NOLINT

	// A POD (plain old data) object has one of these data types:
	// a fundamental type, union, struct, array,
	// or class--with no constructor. PODs don't have virtual functions or
	// virtual bases.

	// Test to see if the type has constructors.
	union CtorTest {
		T t;
		int i;
	};

	// TODO: There might be a way to test if the type has virtuals
	// For now, if we zero a type with virtuals by mistake, it is going to crash
	// predictable at run-time when the virtuals are called.

	memset(&p, 0, sizeof(T));
}

inline void SecureSetZero(CString* p) {
	ASSERT1(p);
	if (!p->IsEmpty()) {
		::SecureZeroMemory(p->GetBufferSetLength(p->GetLength()),
			p->GetLength() * sizeof(TCHAR));
		p->ReleaseBuffer();
	}
}

inline void SecureSetZero(CComVariant* p) {
	ASSERT1(p);
	ASSERT1(V_VT(p) == VT_BSTR);
	uint32 byte_len = ::SysStringByteLen(V_BSTR(p));
	if (byte_len > 0) {
		::SecureZeroMemory(V_BSTR(p), byte_len);
	}
}

// CreateForegroundParentWindowForUAC creates a WS_POPUP | WS_VISIBLE with zero
// size, of the STATIC WNDCLASS. It uses the default running EXE module
// handle for creation.
//
// A visible centered foreground window is needed as the parent in Windows 7 and
// above, to allow the UAC prompt to come up in the foreground, centered.
// Otherwise, the elevation prompt will be minimized on the taskbar. A zero size
// window works. A plain vanilla WS_POPUP allows the window to be free of
// adornments. WS_EX_TOOLWINDOW prevents the task bar from showing the
// zero-sized window.
//
// Returns NULL on failure. Call ::GetLastError() to get extended error
// information on failure.
inline HWND CreateForegroundParentWindowForUAC()
{
	CWindow foreground_parent;
	if (foreground_parent.Create(_T("STATIC"), NULL, NULL, NULL,
		WS_POPUP | WS_VISIBLE, WS_EX_TOOLWINDOW)) {
			foreground_parent.CenterWindow(NULL);
			::SetForegroundWindow(foreground_parent);
	}
	return foreground_parent.Detach();
}

// TODO: move the definition and ShellExecuteExEnsureParent function
// below into shell.h

#if (NTDDI_VERSION < NTDDI_WINXPSP1)
// This value is not defined in the header, but has no effect on older OSes.
#define SEE_MASK_NOZONECHECKS      0x00800000
#endif

// ShellExecuteExEnsureParent is a wrapper around ::ShellExecuteEx.
// It ensures that we always have a parent window. In elevation scenarios, we
// need to use the HWND property to be acknowledged as a foreground application
// on Windows Vista. Otherwise, the elevation prompt will appear minimized on
// the taskbar The UAC elevation mechanism uses the HWND as part of determining
// whether the elevation is a foreground elevation.
//
// A better place for this might be in the Process class. However, to
// reduce dependencies for the stub, placing this in utils.
//
// Return values:
//   ShellExecuteExEnsureParent returns TRUE on success, and FALSE on failure.
//   Call ::GetLastError() to get the extended error information on failure.
//
// Args:
//   shell_exec_info structure pointer, filled in, with an optional HWND.
//   The structure is not validated. If the HWND is NULL, it creates one.
bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info);

//
// Wait with a message loop.
// Returns true if the wait completed successfully and false in case of an
// error.
//

// Waits with a message loop until any of the synchronization objects is
// signaled. Return the index of the object that satisfied the wait.
bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos);

// Waits with message loop until all the synchronization objects are signaled.
bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles);

// Waits with message loop until the synchronization object is signaled.
bool WaitWithMessageLoop(HANDLE h);

// Waits with message loop for a certain period of time
bool WaitWithMessageLoopTimed(DWORD ms);

//
// TODO: message handler classes should go in other module.
//
// Handles windows messages
class MessageHandlerInterface {
public:
	virtual ~MessageHandlerInterface() {}
	// Does the translate/dispatch for one window message
	// msg is never NULL.
	virtual void Process(MSG* msg) = 0;
};

// The simplest working implementation of a message handler.
// It does TranslateMessage/DispatchMessage.
class BasicMessageHandler : public MessageHandlerInterface {
public:
	BasicMessageHandler() {}
	virtual void Process(MSG* msg);
private:
	DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandler);
};

// An internal detail (used to handle messages
// and adjust the handles/cnt as needed).
class MessageHandlerInternalInterface {
public:
	virtual ~MessageHandlerInternalInterface() {}
	// Does the translate/dispatch for one window message
	// msg is never NULL and may change the handles and cnt (which are
	// never NULL).
	virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt) = 0;
};

// The callback for MessageLoopInterface::RegisterWaitForSingleObject
class WaitCallbackInterface {
public:
	virtual ~WaitCallbackInterface() {}
	// Return false from this method to terminate the message loop.
	virtual bool HandleSignaled(HANDLE handle) = 0;
};

// This is similar to a threadpool interface
// but this is done on the main message loop instead.
//
// Important: These method calls are *not* threadsafe and
// should only be done on the message loop thread.
class MessageLoopInterface {
public:
	virtual ~MessageLoopInterface() {}
	// sets-up a callback for when the handle becomes signaled
	//   * the callback happens on the main thread.
	//   * the handle/callback is removed when
	//     the callback is made.
	//   * If the handle becomes invalid while it is being waited on,
	//     the message loop will exit.
	//   * If the handle has already been registered,
	//     then adding it again will essentially replace the
	//     previous callback with the new one.
	virtual bool RegisterWaitForSingleObject(HANDLE handle,
		WaitCallbackInterface* callback) = 0;

	// stops watching for the handle to be signaled
	virtual bool UnregisterWait(HANDLE handle) = 0;
};

// An implementation of the MessageLoopInterface
class MessageLoopWithWait : public MessageLoopInterface,
	private MessageHandlerInternalInterface {
public:
	MessageLoopWithWait();

	// This method needs to be called before the "Process()"
	// method or else "Process()" will crash.
	//
	// Args:
	//    message_handler: handles any messages that occur
	//       *Note* It is the callers responsibility to keep
	//       message_handler around while this class exists
	//       and the *caller* should free message_handler
	//       after that.
	void set_message_handler(MessageHandlerInterface* message_handler);

	// sets-up a callback for when the handle becomes signaled
	virtual bool RegisterWaitForSingleObject(HANDLE handle,
		WaitCallbackInterface* callback);

	// stops watching for the handle to be signaled
	virtual bool UnregisterWait(HANDLE handle);

	// The message loop and handle callback routine
	HRESULT Process();

private:
	// Handles one messgae and adjus tthe handles and cnt as appropriate after
	// handling the message
	virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt);

	void RemoveHandleAt(uint32 pos);

	MessageHandlerInterface* message_handler_;

	// Handles that are checked for being signaled.
	std::vector<HANDLE> callback_handles_;

	// What to call when a handle is signaled.
	std::vector<WaitCallbackInterface*> callbacks_;
	DISALLOW_EVIL_CONSTRUCTORS(MessageLoopWithWait);
};

// Calls an entry point that may be exposed from a DLL
//   It is an error if the DLL is missing or can't be loaded
//   If the entry point is missing the error returned is
//   ERROR_INVALID_FUNCTION (as an HRESULT).
//   Otherwise, if the function is called successfully then
//   CallEntryPoint0 return S_OK and the result parameter is set to the
//   return value from the function call.
HRESULT CallEntryPoint0(const TCHAR* dll_path,
						const char* function_name,
						HRESULT* result);

// (Un)Registers a COM DLL with the system.  Returns S_FALSE if entry
// point missing (so that it you can call (Un)RegisterDll on any DLL
// without worrying whether the DLL is actually a COM server or not).
HRESULT RegisterDll(const TCHAR* dll_path);
HRESULT UnregisterDll(const TCHAR* dll_path);

// (Un)Registers a COM Local Server with the system.
HRESULT RegisterServer(const TCHAR* exe_path);
HRESULT UnregisterServer(const TCHAR* exe_path);
HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line);

// (Un)Registers a COM Service with the system.
HRESULT RegisterService(const TCHAR* exe_path);
HRESULT UnregisterService(const TCHAR* exe_path);

// Starts a service.
HRESULT RunService(const TCHAR* service_name);

// Read an entire file into a memory buffer. Use this function when you need
// exclusive access to the file.
// Returns MEM_E_INVALID_SIZE if the file size is larger than max_len (unless
// max_len == 0, in which case it is ignored)
HRESULT ReadEntireFile(const TCHAR* filepath,
					   uint32 max_len,
					   std::vector<byte>* buffer_out);

// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,
// this is identical to ReadEntireFile.
HRESULT ReadEntireFileShareMode(const TCHAR* filepath,
								uint32 max_len,
								DWORD share_mode,
								std::vector<byte>* buffer_out);

// Writes an entire file from a memory buffer
HRESULT WriteEntireFile(const TCHAR * filepath,
						const std::vector<byte>& buffer_in);

// Conversions between a byte stream and a std::string
HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out);
HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out);
HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out);
HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out);

// Splits a "full regkey name" into a key name part and a value name part.
// Handles "(default)" as a value name.  Treats a trailing "/" as "(default)".
HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,
							 CString* key_name,
							 CString* value_name);

// Expands string with embedded special variables which are enclosed
// in '%' pair. For example, "%PROGRAMFILES%\Google" expands to
// "C:\Program Files\Google".
// If any of the embedded variable can not be expanded, we will leave it intact
// and return HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
HRESULT ExpandEnvLikeStrings(const TCHAR* src,
							 const std::map<CString, CString>& keywords,
							 CString* dest);

// Returns true if the path represents a registry path.
bool IsRegistryPath(const TCHAR* path);

// Returns true if the path is a URL.
bool IsUrl(const TCHAR* path);

// Converts GUID to string.
CString GuidToString(const GUID& guid);

// Converts string to GUID.
HRESULT StringToGuidSafe(const CString& str, GUID* guid);

// Converts a variant containing a list of strings.
void VariantToStringList(VARIANT var, std::vector<CString>* list);

// Appends two registry key paths, takes care of extra separators in the
// beginning or end of the key.
CString AppendRegKeyPath(const CString& one, const CString& two);
CString AppendRegKeyPath(const CString& one,
						 const CString& two,
						 const CString& three);

// Returns the list of user keys that are present within the HKEY_USERS key
// the method only returns the keys of the users and takes care of,
// removing the well known sids. The returned values are the complete values
// from the root of the registry
HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names);

// Use when a function should be able to
// be replaced with another implementation. Usually,
// this is done for testing code only.
//
// Typical usage:
//
//  typedef bool BoolPreferenceFunctionType();
//  CallInterceptor<BoolPreferenceFunctionType> should_send_stats_interceptor;
//  BoolPreferenceFunctionType* ReplaceShouldSendStatsFunction(
//      BoolPreferenceFunctionType* replacement) {
//    return should_send_stats_interceptor.ReplaceFunction(replacement);
//  }
template <typename R>
class CallInterceptor {
public:
	CallInterceptor() {
		interceptor_ = NULL;
	}

	R* ReplaceFunction(R* replacement) {
		R* old = interceptor_;
		interceptor_ = replacement;
		return old;
	}

	R* interceptor() {
		return interceptor_;
	}

private:
	R* interceptor_;
	DISALLOW_EVIL_CONSTRUCTORS(CallInterceptor);
};

// Gets a handle of the current process. The handle is a real handle
// and the caller must close it
HRESULT GetCurrentProcessHandle(HANDLE* handle);

// Duplicates the given token from the source_process into the current process.
HRESULT DuplicateTokenIntoCurrentProcess(HANDLE source_process,
										 HANDLE token_to_duplicate,
										 CAccessToken* duplicated_token);

// Helper class for an ATL module that registers a custom AccessPermission
// to allow local calls from interactive users and the system account.
// Derive from this class as well as CAtlModuleT (or a derivative).
// Override RegisterAppId() and UnregisterAppId(), and delegate to the
// corresponding functions in this class.
template <class T>
class LocalCallAccessPermissionHelper {
public:
	HRESULT RegisterAppId() throw() {
		// Local call permissions allowed for Interactive Users and Local System
		static LPCTSTR ALLOW_LOCAL_CALL_SDDL =
			_T("O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)");

		UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")));

		// First call the base ATL module implementation, so the AppId is registered
		RET_IF_FAILED(T::UpdateRegistryAppId(TRUE));

		// Next, write the AccessPermission value
		RegKey key_app_id;
		RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));

		RegKey key;
		RET_IF_FAILED(key.Create(key_app_id.Key(), T::GetAppIdT()));
		CSecurityDesc sd;
		RET_IF_FALSE(sd.FromString(ALLOW_LOCAL_CALL_SDDL), HRESULTFromLastError());
		RET_IF_FAILED(key.SetValue(
			_T("AccessPermission"),
			reinterpret_cast<const byte*>(sd.GetPSECURITY_DESCRIPTOR()),
			sd.GetLength()));

		UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")
			_T("[succeeded]")));
		return S_OK;
	}

	HRESULT UnregisterAppId() throw() {
		// First remove the AccesPermission entry.
		RegKey key_app_id;
		RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));

		RegKey key;
		RET_IF_FAILED(key.Open(key_app_id.Key(), T::GetAppIdT(), KEY_WRITE));
		VERIFY1(SUCCEEDED(key.DeleteValue(_T("AccessPermission"))));

		// Now, call the base ATL module implementation to unregister the AppId
		RET_IF_FAILED(T::UpdateRegistryAppId(FALSE));

		UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::UnregisterAppId'")
			_T("[succeeded]")));
		return S_OK;
	}
};

// Returns true if the argument is a guid.
inline bool IsGuid(const TCHAR* s) {
	if (!s) return false;
	GUID guid = {0};
	return SUCCEEDED(StringToGuidSafe(s, &guid));
}

inline bool IsLocalSystemSid(const TCHAR* sid) {
	ASSERT1(sid);
	return _tcsicmp(sid, kLocalSystemSid) == 0;
}

// Fills a buffer with cryptographically random bytes.
bool GenRandom(void* buffer, size_t buffer_length);

// Deletes an object. The functor is useful in for_each algorithms.
struct DeleteFun {
	template <class T> void operator()(T ptr) { delete ptr; }
};

// Sets or clears the specified value in the Run key to the specified command.
HRESULT ConfigureRunAtStartup(const CString& root_key_name,
							  const CString& run_value_name,
							  const CString& command,
							  bool install);

// Cracks a command line and returns the program name, which is the first
// whitespace separated token.
HRESULT GetExePathFromCommandLine(const TCHAR* command_line,
								  CString* exe_path);

// Waits for MSI to complete, if MSI is busy installing or uninstalling apps.
HRESULT WaitForMSIExecute(int timeout_ms);

// Returns the value of the specified environment variable.
CString GetEnvironmentVariableAsString(const TCHAR* name);

// Returns true if the OS is installing (e.g., Audit Mode at an OEM factory).
// NOTE: This is unreliable on Windows Vista and later. Some computers remain in
// one of the incomplete states even after OOBE. See http://b/1690617.
bool IsWindowsInstalling();

// TODO: unit test.
inline uint64 GetGuidMostSignificantUint64(const GUID& guid) {
	return (static_cast<uint64>(guid.Data1) << 32) +
		(static_cast<uint64>(guid.Data2) << 16) +
		static_cast<uint64>(guid.Data3);
}

// Calls either ATL::InterlockedExchangePointer if ATL headers are included,
// or ::InterlockedExchangePointer. ATL slightly redefines the SDK function
// with the same name.
template <typename T>
inline T* interlocked_exchange_pointer(T* volatile * target,
									   const T* value)
{
	return static_cast<T*>(InterlockedExchangePointer(
		reinterpret_cast<void**>(const_cast<T**>(target)),
		const_cast<T*>(value)));
}

// Gets a guid from the system (for user id, etc.)
// The guid will be of the form: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
HRESULT GetGuid(CString* guid);

// Returns the message for an error code in the user's language or an
// empty string if an error occurs. The function does not support
// "insert sequences". The sequence will be returned in the string.
CString GetMessageForSystemErrorCode(DWORD error_code);

// Ceil function for integer types. Returns the quotient of the two
// numbers (m/n) rounded upwards to the nearest integer.
// T should be unsigned integer type, such as unsigned short, unsigned long,
// unsigned int etc.
template <typename T>
inline T CeilingDivide(T m, T n) {
	ASSERT1(n != 0);

	return (m + n - 1) / n;
}

#endif	// LONGKEY_BASE_UTILS_H_